<template>
  <el-table
    ref="tableRef"
    v-bind="$attrs"
    :data="data"
    v-loading="$attrs.loading"
    @select-all="selectAll"
    @select="select"
    @row-click="rowClick"
    :header-cell-style="headerCellStyle"
  >
    <el-table-column
      v-if="selection"
      type="selection"
      :selectable="setDisabled"
      width="50"
      :resizable="resizable"
    ></el-table-column>
    <el-table-column v-if="radio" width="40" :resizable="resizable">
      <template #default="{ row }">
        <el-radio
          :disabled="disabledKeys.includes(row[rowKey])"
          v-model="newRadioKey"
          :label="row[rowKey]"
          name="radio"
        >
          <span style="padding: 0 30px"></span>
        </el-radio>
      </template>
    </el-table-column>
    <el-table-column
      v-if="showIndex"
      label="序号"
      width="90"
      :resizable="resizable"
    >
      <template #default="{ $index }"> {{ $index + 1 }}</template>
    </el-table-column>
    <template v-for="(item, index) in newColumn" :key="index">
      <el-table-column
        :show-overflow-tooltip="$attrs.showTooltip || item.showTooltip"
        v-if="isTrue(item.display)"
        :label="item.label"
        :width="item.width"
        :prop="item.prop"
        :fixed="item.fixed || null"
        :align="item.align || 'left'"
        :resizable="resizable"
      >
        <template #default="scope">
          <slot
            v-if="item.slot"
            :name="item.prop"
            :row="scope.row"
            :index="scope.$index"
          ></slot>
          <template v-else>{{ scope.row[item.prop] }}</template>
        </template>
      </el-table-column>
    </template>
  </el-table>
  <el-row
    style="margin-top: 20px"
    :justify="justify"
    v-if="'pagination' in $attrs"
  >
    <uc-pagination
      :total="$attrs.total - 0"
      v-model="newPageList"
      @change="changePage"
    ></uc-pagination>
  </el-row>
</template>

<script setup>
import { ref, toRaw, nextTick, watch, computed, onMounted } from "vue";
import { isTrue, duplicateArr } from "../../lib";
const emits = defineEmits([
  "update:pageList",
  "update:modelValue",
  "update:selectData",
  "update:radioKey",
  "changePage",
  "clickRow",
]);
/* eslint-disable */
const props = defineProps({
  // 表格配置项
  column: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 表格数据项
  data: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 表格数据项唯一标识
  rowKey: {
    type: String,
    default: "id",
  },
  // 多选默认选中的值-唯一标识数组
  modelValue: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 多选选中的数据列表
  selectData: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 表格border为true时是否可以拖动
  resizable: {
    type: Boolean,
    default: true,
  },
  // 是否显示索引
  showIndex: {
    type: Boolean,
    default: false,
  },
  // 是否可以多选
  selection: {
    type: Boolean,
    default: false,
  },
  // 默认选择的值是否禁用
  selectable: {
    type: Boolean,
    default: false,
  },
  // 是否显示单选框
  radio: {
    type: Boolean,
    default: false,
  },
  // 表格单选值
  radioKey: {
    type: String,
    default: "",
  },
  // 被禁用项标识
  disabledKeys: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 点击表格行是否可以选中单选或多选
  isRowClick: {
    type: Boolean,
    default: false,
  },
  // 分页信息
  pageInfo: {
    type: Object,
    default: () => {
      return {};
    },
  },
  // 分页布局
  justify: {
    type: String,
    default: "center",
  },
  // 表格表头背景
  headerCellStyle: {
    type: Object,
    default: () => {
      return {
        backgroundColor: "#f5f5f5",
      };
    },
  },
});
let isActionWidth = false;
onMounted(() => {
  isActionWidth = (newColumn.value.find((item) => item.prop === "action") || {})
    .width;
});

const newColumn = ref([]);
watch(
  () => props.column,
  (val) => {
    if (val.length > 0) {
      newColumn.value = val;
    }
  },
  {
    immediate: true,
  }
);

/**
 * 监听表格整个数据的变化，并处理多选默认选中项
 */
let selectData = props.selectData;
watch(
  () => props.data,
  (newValue) => {
    if (
      newValue &&
      newValue.length > 0 &&
      props.modelValue.length > 0 &&
      props.selection
    ) {
      // 与当前页数据进行匹配，找出默认选中的表格项数据
      const selection = newValue.filter((item) =>
        props.modelValue.includes(item[props.rowKey])
      );
      // 切换分页时对选择的值去重
      selectData = duplicateArr(selectData.concat(selection), props.rowKey);
      emits("update:chooseKeys", selectData);
      nextTick(() => {
        toggleSelection(selection);
      });
    }
    if (newValue && newValue.length > 0) {
      setTimeout(() => {
        setActionWidth();
      });
    }
  },
  {
    immediate: true,
  }
);

/**
 * 表格单选项
 * 同步更新单选项的值
 */
const newRadioKey = computed({
  get() {
    return props.radioKey;
  },
  set(val) {
    console.log(val);
    emits("update:radioKey", val);
  },
});
/**
 * 处理表格默认选中项
 */
const tableRef = ref(null);
const toggleSelection = (rows) => {
  try {
    if (rows.length > 0) {
      rows.forEach((row) => {
        tableRef.value.toggleRowSelection(row, undefined);
      });
    } else {
      tableRef.value.clearSelection();
    }
  } catch (err) {}
};

/**
 * 监听表格全选反选
 */
let autoModelValue = structuredClone(toRaw(props.modelValue));
const selectAll = (newVal) => {
  let newValue = props.modelValue;
  // 匹配当前页默认选中项被禁用标识, 不能被取消
  const autoIds = autoModelValue.filter((item) =>
    props.data.some((_item) => _item[props.rowKey] == item)
  );
  if (newVal.length > 0) {
    if (newVal.length == autoIds.length) {
      // 如果选中的项为被禁用的项，则为反选操作，需要移除被禁用项的标识
      const ids = props.data
        .map((item) => {
          return item[props.rowKey];
        })
        .filter((item) => autoIds.some((_item) => _item !== item));
      newValue = newValue.filter((item) => !ids.includes(item));
      selectData = selectData.filter(
        (item) => !ids.includes(item[props.rowKey])
      );
    } else {
      // 全选
      const selectVal = newVal.map((item) => {
        return item[props.rowKey];
      });
      newValue = [...new Set(newValue.concat(selectVal))];
      // 全选去除重复的
      selectData = duplicateArr(selectData.concat(newVal), props.rowKey);
    }
  } else {
    // 反选，拿到当前所有id去除
    const ids = props.data.map((item) => {
      return item[props.rowKey];
    });
    newValue = newValue.filter((item) => !ids.includes(item));
    selectData = selectData.filter((item) => !ids.includes(item[props.rowKey]));
  }
  emits("update:selectData", selectData);
  emits("update:modelValue", newValue);
};

/**
 * 监听表格项单个多选表单项操作
 */
const select = (val, row) => {
  selectTable(row);
  emits("clickRow", toRaw(row), val);
};

/**
 * 监听点击表格项事件
 */
const rowClick = (row) => {
  emits("clickRow", toRaw(row));
  if (props.isRowClick) {
    selectTable(row, false);
  }
};

/**
 * 点击表格多选框或表格项时触发，当前项禁用时禁止触发
 * @param { object } row 点击表格当前项
 * @param { boolean } isCheckBox 点击多选框或者表格项
 */
const selectTable = (row, isCheckBox = true) => {
  const disabledArr = props.selection
    ? [...autoModelValue, ...props.disabledKeys]
    : props.disabledKeys;
  const id = row[props.rowKey];
  if (props.radio && disabledArr.indexOf(id) == -1) {
    emits("update:radioKey", id);
  }
  if (props.selection && disabledArr.indexOf(id) == -1) {
    const newValue = structuredClone(toRaw(props.modelValue));
    const index = props.modelValue.findIndex(
      (item) => item == row[props.rowKey]
    );
    console.log(index);
    if (index == -1) {
      selectData.push(row);
      newValue.push(row[props.rowKey]);
      if (!isCheckBox) tableRef.value.toggleRowSelection(row, undefined);
    } else {
      selectData.splice(index, 1);
      newValue.splice(index, 1);
      if (!isCheckBox) tableRef.value.toggleRowSelection(row);
    }
    emits("update:selectData", selectData);
    emits("update:modelValue", newValue);
  }
};

/**
 * 多选框是否禁用
 * 包括默认选中项和自定义禁止项
 */
const setDisabled = (row) => {
  const arr = props.selectable
    ? [...autoModelValue, ...props.disabledKeys]
    : props.disabledKeys;
  if (arr.includes(row[props.rowKey])) {
    return false;
  } else {
    return true;
  }
};

/**
 * 分页数据处理
 * 分页点击操作
 */
const newPageList = computed({
  get() {
    return props.pageInfo;
  },
  set(val) {
    emits("update:pageList", val);
  },
});
const changePage = (val) => {
  emits("changePage", val);
};

/**
 * 修改表格项配置
 */
const modifyTableColumn = (obj) => {
  for (let key in obj) {
    const index = newColumn.value.findIndex((item) => item.prop === key);
    if (index === -1) return;
    for (let prop in obj[key]) {
      newColumn.value[index][prop] = obj[key][prop];
    }
  }
};

/**
 * 动态修改表格操作项宽度, 如果设置宽度则直接使用，为设置宽度使用动态宽度
 */
const setActionWidth = () => {
  const index = newColumn.value.findIndex((item) => item.prop === "action");
  const actionBtn = document.querySelectorAll(".action-btn-width");
  if (!index || isActionWidth || actionBtn.length == 0) return;
  const textArr = [];
  const btnNumArr = [];
  actionBtn.forEach((item) => {
    textArr.push(item.textContent);
    btnNumArr.push(item.outerText.split("\n").length);
  });
  const textLen = textArr.map((item) => item.length);
  const maxText = textArr[textLen.indexOf(Math.max(...textLen))];
  const maxBtn = Math.max(...btnNumArr);
  const width = 24 + (maxBtn - 1) * 9 + maxText.length * 14;
  // 14为字体大小
  newColumn.value[index].width = width;
};

defineExpose({
  modifyTableColumn,
  setActionWidth,
});
</script>

<style lang="scss" scoped>
:deep(.el-popper) {
  max-width: 300px !important;
}
</style>
